package com.dashan.backend.datastore;

import static com.dashan.Constants.DEFAULT_STATUS;
import static com.dashan.Constants.FULL_PERMISSION;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.dashan.backend.DashanException;
import com.dashan.backend.XmlSerializable;
import com.google.appengine.api.datastore.Key;


@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class DsUser implements XmlSerializable {
    @PrimaryKey
    @Persistent
    private String userName;
    
    @Persistent
    private String nickName;
    
    @Persistent
    private String pwdSha;
    
    @Persistent
    private Key position;

    @Persistent
    private Key status;
    
    @Persistent
    private Set<DsFriend> friends;
    
    @Persistent
    private Set<DsFriendGroup> friendGroups;

    @Persistent
    private DsUserProfile profile;
    
    // Constructors
    protected DsUser(String userName, String nickName, String pwdSha) {
        this.userName = userName;
        this.nickName = nickName;
        this.pwdSha = pwdSha;
        this.friendGroups = new HashSet<DsFriendGroup>();
        this.profile = new DsUserProfile(userName);
    }
    
    // Setters and Getters
    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getPwdSha() {
        return pwdSha;
    }

    public void setPwdSha(String pwdSha) {
        this.pwdSha = pwdSha;
    }

    public DsPosition getPosition() {
        if (position == null) {
            return null;
        }
        
        PositionHistoryDao dao = new PositionHistoryDao();
        DsPosition p = dao.getPosisionByKey(position);
        dao.commit();
        return p;
    }

    public void setPosition(DsPosition position) {
        
        PositionHistoryDao dao = new PositionHistoryDao();
        dao.addPosition(position);
        dao.commit();
        this.position = position.getKey();
    }

    public DsStatus getStatus() {
        if (status == null) {
            return null;
        }
        StatusHistoryDao dao = new StatusHistoryDao();
        DsStatus s = dao.getStatusByKey(status);
        dao.commit();
        return s;
    }

    public void setStatus(DsStatus status) {
        StatusHistoryDao dao = new StatusHistoryDao();
        dao.addStatus(status);
        dao.commit();
        this.status = status.getKey();
    }
    
    public Set<DsFriend> getFriends() {
        if (friends == null) {
            friends = new HashSet<DsFriend>();
        }
        return Collections.unmodifiableSet(friends);
    }
    
    public DsFriend getFriend(String friendName) {
        for (DsFriend friend : getFriends()) {
            if (friend.getFriendName().compareTo(friendName) == 0) {
                return friend;
            }
        }
        return null;
    }
    
    public DsFriendGroup getGroup(String groupName) {
        for (DsFriendGroup g : getFriendGroups()) {
            if (g.getGroupName().compareTo(groupName) == 0) {
                return g;
            }
        }
        return null;
    }
    
    /**
     * DO NOT use this function to remove group directly. Please us
     * FriendManager.addFriend() instead.
     **/
    public void addFriend(String friendName) throws DashanException {        
        if (getFriend(friendName) == null) {
            friends.add(new DsFriend(userName, friendName));
        }
    }
    
    public Set<DsFriendGroup> getFriendGroups() {
        return Collections.unmodifiableSet(friendGroups); 
    }
    
    /**
     * DO NOT use this function to add group directly. Please us
     * FriendManager.createGroup() instead.
     **/
    public void addGroup(DsFriendGroup group) throws DashanException {
        if (getGroup(group.getGroupName()) != null) {
            throw new DashanException("Group already exist: " + group.getGroupName());
        }    
        friendGroups.add(group);
    }
    
    public void addGroup(String groupName) throws DashanException {
        addGroup(new DsFriendGroup(userName, groupName, FULL_PERMISSION));
    }
    
    public void addGroup(String groupName, long permission) throws DashanException {
        addGroup(new DsFriendGroup(userName, groupName, permission));
    }
    
    /**
     * DO NOT use this function to remove group directly. Please us
     * FriendManager.removeGroup() instead.
     * @throws DashanException 
     **/
    public void removeGroup(DsFriendGroup group) {
        friendGroups.remove(group);
    }

    public Element getXmlElement(Document xmlDoc) {
        Element root = xmlDoc.createElement("user");
        
        Element ele = null;
        
        ele = xmlDoc.createElement("userName");
        ele.appendChild(xmlDoc.createTextNode(getUserName()));
        root.appendChild(ele);
        ele = xmlDoc.createElement("nickName");
        ele.appendChild(xmlDoc.createTextNode(getNickName()));
        root.appendChild(ele);
        ele = xmlDoc.createElement("status");
        if (getStatus() != null && getStatus().getMessage() != null) {
            ele.appendChild(xmlDoc.createTextNode(getStatus().getMessage()));
        } else {
            ele.appendChild(xmlDoc.createTextNode(DEFAULT_STATUS));
        }
        root.appendChild(ele);            
        
        if (position != null) {
            root.appendChild(getPosition().getXmlElement(xmlDoc));
        }
        if (friendGroups != null) {
            Element group = xmlDoc.createElement("friendGroups");
            for (DsFriendGroup g : friendGroups) {
                group.appendChild(g.getXmlElement(xmlDoc));
            }
            root.appendChild(group);
        }
        return root;
    }

    public DsUserProfile getProfile() {
        return profile;
    }
}
